package com.dev.weixin.tools.service.impl;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.dev.weixin.tools.models.WeixinConfig;
import com.dev.weixin.tools.models.base.ErrorMsg;
import com.dev.weixin.tools.models.exceptions.ErrorMsgException;
import com.dev.weixin.tools.models.user.Group;
import com.dev.weixin.tools.models.user.GroupData;
import com.dev.weixin.tools.models.user.GroupsData;
import com.dev.weixin.tools.models.user.Oauth2AccessToken;
import com.dev.weixin.tools.models.user.Oauth2UserInfo;
import com.dev.weixin.tools.models.user.SearchResult;
import com.dev.weixin.tools.models.user.UserInfo;
import com.dev.weixin.tools.models.user.UserList;
import com.dev.weixin.tools.service.BaseService;
import com.dev.weixin.tools.service.UserService;
import com.dev.weixin.tools.utils.URLConstants;
import com.dev.weixin.tools.utils.WeixinHttpClient;
import com.dev.weixin.tools.utils.policy.GetRequestPolicy;
import com.dev.weixin.tools.utils.policy.JsonRequestPolicy;
import com.dev.weixin.tools.utils.policy.RequestPolicy;

/**
 * @author 飘渺青衣
 * @see
 */
@Service("weixinUserService")
public class UserServiceImpl implements UserService {
	
	private BaseService baseService;
	
	@Autowired
	public UserServiceImpl(BaseService baseService) {
		this.baseService = baseService;
	}

	/* (non-Javadoc)
	 * @see com.dev.weixin.tools.service.UserService#createGroup(com.dev.weixin.tools.models.user.Group)
	 */
	@Override
	public Group createGroup(Group group) throws ErrorMsgException {
		Map<String, String> params = new HashMap<String, String>();
		params.put("access_token", this.baseService.getAccessToken());
		RequestPolicy<GroupData> policy = new JsonRequestPolicy<GroupData>(
				URLConstants.User.URL_GROUP_CREATE, 
				WeixinConfig.ENCODING,
				params, group, GroupData.class);
		GroupData result =  WeixinHttpClient.request(policy);
		return result != null ? result.getGroup() : null;
	}

	/* (non-Javadoc)
	 * @see com.dev.weixin.tools.service.UserService#getGroups()
	 */
	@Override
	public List<Group> getGroups() throws ErrorMsgException {
		Map<String, String> params = new HashMap<String, String>();
		params.put("access_token", this.baseService.getAccessToken());
		RequestPolicy<GroupsData> policy = new GetRequestPolicy<GroupsData>(
				URLConstants.User.URL_GROUP_GET, 
				WeixinConfig.ENCODING,
				params, GroupsData.class);
		GroupsData result =  WeixinHttpClient.request(policy);
		return result != null ? result.getGroups() : null;
	}

	/* (non-Javadoc)
	 * @see com.dev.weixin.tools.service.UserService#getGroupId(java.lang.String)
	 */
	@Override
	public String getGroupId(String openid) throws ErrorMsgException {
		Map<String, String> params = new HashMap<String, String>();
		params.put("access_token", this.baseService.getAccessToken());
		Map<String, String> body = new HashMap<String, String>();
		body.put("openid", openid);
		RequestPolicy<SearchResult> policy = new JsonRequestPolicy<SearchResult>(
				URLConstants.User.URL_GROUP_GETID, 
				WeixinConfig.ENCODING,
				params, body, SearchResult.class);
		SearchResult result =  WeixinHttpClient.request(policy);
		return result != null ? result.getGroupid() : null;
	}

	/* (non-Javadoc)
	 * @see com.dev.weixin.tools.service.UserService#updateGroup(com.dev.weixin.tools.models.user.Group)
	 */
	@Override
	public boolean updateGroup(Group group) throws ErrorMsgException {
		Map<String, String> params = new HashMap<String, String>();
		params.put("access_token", this.baseService.getAccessToken());
		RequestPolicy<ErrorMsg> policy = new JsonRequestPolicy<ErrorMsg>(
				URLConstants.User.URL_GROUP_UPDATE, 
				WeixinConfig.ENCODING,
				params, group, ErrorMsg.class);
		ErrorMsg error = WeixinHttpClient.request(policy);
		boolean isOk = error != null && StringUtils.equals("0", error.getErrcode());
		if(!isOk) {
			throw new ErrorMsgException(error);
		}
		return isOk;
	}

	/* (non-Javadoc)
	 * @see com.dev.weixin.tools.service.UserService#moveUserToGroup(java.lang.String, java.lang.String)
	 */
	@Override
	public boolean moveUserToGroup(String openid, String to_groupid)
			throws ErrorMsgException {
		Map<String, String> params = new HashMap<String, String>();
		params.put("access_token", this.baseService.getAccessToken());
		Map<String, String> body = new HashMap<String, String>();
		body.put("openid", openid);
		body.put("to_groupid", to_groupid);
		RequestPolicy<ErrorMsg> policy = new JsonRequestPolicy<ErrorMsg>(
				URLConstants.User.URL_MEMBERS_UPDATE, 
				WeixinConfig.ENCODING,
				params, body, ErrorMsg.class);
		ErrorMsg error = WeixinHttpClient.request(policy);
		boolean isOk = error != null && StringUtils.equals("0", error.getErrcode());
		if(!isOk) {
			throw new ErrorMsgException(error);
		}
		return isOk;
	}

	/* (non-Javadoc)
	 * @see com.dev.weixin.tools.service.UserService#moveUserToGroup(java.util.List, java.lang.String)
	 */
	@Override
	public boolean moveUserToGroup(List<String> openids, String to_groupid)
			throws ErrorMsgException {
		Map<String, String> params = new HashMap<String, String>();
		params.put("access_token", this.baseService.getAccessToken());
		Map<String, Object> body = new HashMap<String, Object>();
		body.put("openid_list", openids);
		body.put("to_groupid", to_groupid);
		RequestPolicy<ErrorMsg> policy = new JsonRequestPolicy<ErrorMsg>(
				URLConstants.User.URL_MEMBERS_BATCHUPDATE, 
				WeixinConfig.ENCODING,
				params, body, ErrorMsg.class);
		ErrorMsg error = WeixinHttpClient.request(policy);
		boolean isOk = error != null && StringUtils.equals("0", error.getErrcode());
		if(!isOk) {
			throw new ErrorMsgException(error);
		}
		return isOk;
	}

	/* (non-Javadoc)
	 * @see com.dev.weixin.tools.service.UserService#updateUserRemark(java.lang.String, java.lang.String)
	 */
	@Override
	public boolean updateUserRemark(String openid, String remark)
			throws ErrorMsgException {
		Map<String, String> params = new HashMap<String, String>();
		params.put("access_token", this.baseService.getAccessToken());
		Map<String, Object> body = new HashMap<String, Object>();
		body.put("openid", openid);
		body.put("remark", remark);
		RequestPolicy<ErrorMsg> policy = new JsonRequestPolicy<ErrorMsg>(
				URLConstants.User.URL_USER_REMARK, 
				WeixinConfig.ENCODING,
				params, body, ErrorMsg.class);
		ErrorMsg error = WeixinHttpClient.request(policy);
		boolean isOk = error != null && StringUtils.equals("0", error.getErrcode());
		if(!isOk) {
			throw new ErrorMsgException(error);
		}
		return isOk;
	}

	/* (non-Javadoc)
	 * @see com.dev.weixin.tools.service.UserService#getUserInfo(java.lang.String, java.lang.String)
	 */
	@Override
	public UserInfo getUserInfo(String openid, String lang) throws ErrorMsgException {
		Map<String, String> params = new HashMap<String, String>();
		params.put("access_token", this.baseService.getAccessToken());
		params.put("openid", openid);
		params.put("lang", StringUtils.isEmpty(lang) ? "zh_CN" : lang);
		RequestPolicy<UserInfo> policy = new GetRequestPolicy<UserInfo>(
				URLConstants.User.URL_USER_INFO, 
				WeixinConfig.ENCODING,
				params, UserInfo.class);
		return WeixinHttpClient.request(policy);
	}

	/* (non-Javadoc)
	 * @see com.dev.weixin.tools.service.UserService#getUserList(java.lang.String)
	 */
	@Override
	public UserList getUserList(String next_openid) throws ErrorMsgException {
		Map<String, String> params = new HashMap<String, String>();
		params.put("access_token", this.baseService.getAccessToken());
		params.put("next_openid", StringUtils.trimToEmpty(next_openid));
		RequestPolicy<UserList> policy = new GetRequestPolicy<UserList>(
				URLConstants.User.URL_USER_GET, 
				WeixinConfig.ENCODING,
				params, UserList.class);
		return WeixinHttpClient.request(policy);
	}

	/* (non-Javadoc)
	 * @see com.dev.weixin.tools.service.UserService#buildOauth2Url(java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override
	public String buildOauth2Url(String redirect_uri, String scope, String state) throws UnsupportedEncodingException {
		StringBuilder s = new StringBuilder();
		s.append(URLConstants.User.URL_OAUTH2_URL);
		s.append("?appid=").append(this.baseService.getWeixinConfig().getAppId());
		s.append("&redirect_uri=").append(URLEncoder.encode(redirect_uri, "UTF-8"));
		s.append("&response_type=code");
		s.append("&scope=").append(scope);
		if(!StringUtils.isEmpty(state)) {
			s.append("&state=").append("state");
		}
		s.append("#wechat_redirect");
		return s.toString();
	}

	/* (non-Javadoc)
	 * @see com.dev.weixin.tools.service.UserService#getOauth2AccessToken(java.lang.String)
	 */
	@Override
	public Oauth2AccessToken getOauth2AccessToken(String code) throws ErrorMsgException {
		WeixinConfig config = this.baseService.getWeixinConfig();
		Map<String, String> params = new HashMap<String, String>();
		params.put("appid", config.getAppId());
		params.put("secret", config.getAppSecret());
		params.put("code", code);
		params.put("grant_type", "authorization_code");
		RequestPolicy<Oauth2AccessToken> policy = new GetRequestPolicy<Oauth2AccessToken>(
				URLConstants.User.URL_OAUTH2_ACCESSTOKEN, 
				WeixinConfig.ENCODING,
				params, Oauth2AccessToken.class);
		return WeixinHttpClient.request(policy);
	}

	/* (non-Javadoc)
	 * @see com.dev.weixin.tools.service.UserService#refreshOauth2AccessToken(java.lang.String)
	 */
	@Override
	public Oauth2AccessToken refreshOauth2AccessToken(String refresh_token)
			throws ErrorMsgException {
		WeixinConfig config = this.baseService.getWeixinConfig();
		Map<String, String> params = new HashMap<String, String>();
		params.put("appid", config.getAppId());
		params.put("grant_type", "refresh_token");
		params.put("refresh_token", refresh_token);
		RequestPolicy<Oauth2AccessToken> policy = new GetRequestPolicy<Oauth2AccessToken>(
				URLConstants.User.URL_OAUTH2_REFRESHTOKEN, 
				WeixinConfig.ENCODING,
				params, Oauth2AccessToken.class);
		return WeixinHttpClient.request(policy);
	}

	/* (non-Javadoc)
	 * @see com.dev.weixin.tools.service.UserService#getOauth2UserInfo(java.lang.String, java.lang.String)
	 */
	@Override
	public Oauth2UserInfo getOauth2UserInfo(String oauth2_access_token, String openid, String lang)
			throws ErrorMsgException {
		Map<String, String> params = new HashMap<String, String>();
		params.put("access_token", oauth2_access_token);
		params.put("openid", openid);
		params.put("lang", StringUtils.isEmpty(lang) ? "zh_CN" : lang);
		RequestPolicy<Oauth2UserInfo> policy = new GetRequestPolicy<Oauth2UserInfo>(
				URLConstants.User.URL_OAUTH2_SNSUSERINFO, 
				WeixinConfig.ENCODING,
				params, Oauth2UserInfo.class);
		return WeixinHttpClient.request(policy);
	}

	/* (non-Javadoc)
	 * @see com.dev.weixin.tools.service.UserService#checkOauth2AccessToken(java.lang.String, java.lang.String)
	 */
	@Override
	public boolean checkOauth2AccessToken(
			String oauth2_access_token,
			String openid) throws ErrorMsgException {
		Map<String, String> params = new HashMap<String, String>();
		params.put("access_token", oauth2_access_token);
		params.put("openid", openid);
		RequestPolicy<ErrorMsg> policy = new GetRequestPolicy<ErrorMsg>(
				URLConstants.User.URL_OAUTH2_ACCESSTOKENCHECK, 
				WeixinConfig.ENCODING,
				params, ErrorMsg.class);
		ErrorMsg error = WeixinHttpClient.request(policy);
		boolean isOk = error != null && StringUtils.equals("0", error.getErrcode());
		if(!isOk) {
			throw new ErrorMsgException(error);
		}
		return isOk;
	}

}
